`timescale 1ns / 1ps

`include "data_width.vh"

module get_edge_info_pre_1 #(parameter
    DST_ID_DWIDTH = `DST_ID_DWIDTH, VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH,
    TOT_ACC_ID_WIDTH = `TOT_ACC_ID_WIDTH, TOT_EDGE_MASK_WIDTH = `TOT_EDGE_MASK_WIDTH,
    VERTEX_PIPE_NUM = `VERTEX_PIPE_NUM, EDGE_PIPE_NUM = `EDGE_PIPE_NUM
    ) (
        input                                                   clk,
        input                                                   front_rst,
        input                                                   front_finish_read,
        input                                                   front_any_dst_data_valid,
        input [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0]         front_dst_id,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]     front_edge_info_mask_l,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]     front_edge_info_mask_r,
        input [VERTEX_PIPE_NUM - 1 : 0]                         front_dst_data_valid,
        input                                                   back_stage_vertex_full,

        output                                                  rst,
        output                                                  buffer_full_vertex,
        output                                                  finish_read,
        // MASK信号为 16 个，每个宽度为 EDGE_MASK_WIDTH * EDGE_PIPE_NUM
        output [TOT_EDGE_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]  tot_src_p_mask,
        output [TOT_ACC_ID_WIDTH * VERTEX_PIPE_NUM - 1 : 0]     tot_acc_id,
        output [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0]        dst_id,
        output [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]    src_p_mask_r,
        output [VERTEX_PIPE_NUM - 1 : 0]                        dst_data_valid,
        output                                                  any_dst_data_valid);

    wire                            finish_buffer_empty, finish_buffer_full;
    wire [VERTEX_PIPE_NUM - 1 : 0]  edge_buffer_empty, edge_buffer_full;
    wire [VERTEX_PIPE_NUM - 1 : 0]  dst_buffer_empty, dst_buffer_full;
    wire [VERTEX_PIPE_NUM - 1 : 0]  data_valid;

    assign buffer_full_vertex = dst_buffer_full[0];
    assign any_dst_data_valid = data_valid[0];

    get_edge_info_pre_1_para_tran P (
        .clk(clk), .front_rst(front_rst),

        .rst(rst));

    get_edge_info_pre_1_fr F1 (
        .clk                        (clk),
        .rst                        (front_rst),
        .front_finish_read          (front_finish_read),
        .front_any_dst_data_valid   (front_any_dst_data_valid),
        .back_stage_vertex_full     (back_stage_vertex_full),
        .read_next_valid            (!edge_buffer_empty[0]),

        .buffer_empty               (finish_buffer_empty),
        .buffer_full                (finish_buffer_full),
        .finish_read                (finish_read));
    
    generate
        genvar i;
        for (i = 0; i < VERTEX_PIPE_NUM; i = i + 1) begin : M6_1_BLOCK_1
            get_edge_info_pre_1_mask_single # (.FLAG(i)) M (
                .clk(clk), .rst(front_rst),
                .front_edge_info_mask_l(front_edge_info_mask_l[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .front_edge_info_mask_r(front_edge_info_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .front_dst_data_valid(front_dst_data_valid[i]), .front_any_dst_data_valid(front_any_dst_data_valid), .back_stage_vertex_full(back_stage_vertex_full),

                .buffer_empty(edge_buffer_empty[i]), .buffer_full(edge_buffer_full[i]),
                .tot_src_p_mask(tot_src_p_mask[(i + 1) * TOT_EDGE_MASK_WIDTH - 1 : i * TOT_EDGE_MASK_WIDTH]),
                .tot_acc_id(tot_acc_id[(i + 1) * TOT_ACC_ID_WIDTH - 1 : i * TOT_ACC_ID_WIDTH]));
        end
    endgenerate

    generate
        for (i = 0; i < VERTEX_PIPE_NUM; i = i + 1) begin : M6_1_BLOCK_2
            get_edge_info_pre_1_vertex_single V (
                .clk                        (clk),
                .rst                        (front_rst),
                .front_dst_id               (front_dst_id[(i + 1) * DST_ID_DWIDTH - 1 : i * DST_ID_DWIDTH]),
                .front_edge_info_mask_r     (front_edge_info_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .front_dst_data_valid       (front_dst_data_valid[i]),
                .front_any_dst_data_valid   (front_any_dst_data_valid),
                .back_stage_vertex_full     (back_stage_vertex_full),
                .read_next_valid            (!edge_buffer_empty[0]),    // vertex fifo and mask fifo syn

                .buffer_empty               (dst_buffer_empty[i]),
                .buffer_full                (dst_buffer_full[i]),
                .dst_id                     (dst_id[(i + 1) * DST_ID_DWIDTH - 1 : i * DST_ID_DWIDTH]),
                .src_p_mask_r               (src_p_mask_r[(i + 1) * VERTEX_MASK_WIDTH - 1 : i * VERTEX_MASK_WIDTH]),
                .dst_data_valid             (dst_data_valid[i]),
                .data_valid                 (data_valid[i]));
        end
    endgenerate

endmodule

module get_edge_info_pre_1_para_tran (
    input       clk,
    input       front_rst,

    output reg  rst);

    always @ (posedge clk) begin
        rst <= front_rst;
    end

endmodule

module get_edge_info_pre_1_fr (
    input clk,
    input rst,
    input front_finish_read,
    input front_any_dst_data_valid,
    input back_stage_vertex_full,
    input read_next_valid,

    output buffer_empty,
    output buffer_full,
    output finish_read);

    finish_read_fifo geip1f_frf (
        .clk        (clk),
        .srst       (rst),
        .din        (front_finish_read),
        .wr_en      (front_any_dst_data_valid),
        .rd_en      (!back_stage_vertex_full & read_next_valid),

        .dout       (finish_read),
        .empty      (buffer_empty),
        .prog_full  (buffer_full));

endmodule

module get_edge_info_pre_1_mask_single #(parameter
    FLAG = 5'b00000,
    EDGE_PIPE_NUM = `EDGE_PIPE_NUM,
    VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH,
    EDGE_MASK_WIDTH = `EDGE_MASK_WIDTH, ACC_ID_WIDTH = `ACC_ID_WIDTH,
    PIPE_BUFFER_SIZE = `PIPE_BUFFER_SIZE, PIPE_BUFFER_PTR_WIDTH = `PIPE_BUFFER_PTR_WIDTH, PIPE_AM_LEVEL = `PIPE_AM_LEVEL
    ) (
        input clk,
        input rst,
        input [VERTEX_MASK_WIDTH - 1 : 0] front_edge_info_mask_l,
        input [VERTEX_MASK_WIDTH - 1 : 0] front_edge_info_mask_r,
        input front_dst_data_valid,
        input front_any_dst_data_valid,
        input back_stage_vertex_full,

        output buffer_empty,
        output buffer_full,
        output reg [EDGE_MASK_WIDTH * EDGE_PIPE_NUM - 1 : 0] tot_src_p_mask,
        output reg [ACC_ID_WIDTH * EDGE_PIPE_NUM - 1 : 0] tot_acc_id);

    wire [VERTEX_MASK_WIDTH - 1 : 0] top_edge_info_mask_l;
    wire [VERTEX_MASK_WIDTH - 1 : 0] top_edge_info_mask_r;
    wire [VERTEX_MASK_WIDTH - 1 : 0] lf_in = front_dst_data_valid ? front_edge_info_mask_l : {VERTEX_MASK_WIDTH{1'b1}};
    wire [VERTEX_MASK_WIDTH - 1 : 0] rf_in = front_dst_data_valid ? front_edge_info_mask_r : {VERTEX_MASK_WIDTH{1'b0}};

    edge_info_mask_fifo_fall_through lf (
        .clk(clk), .srst(rst),
        .din(lf_in), .wr_en(front_any_dst_data_valid), .rd_en(!back_stage_vertex_full),

        .dout(top_edge_info_mask_l),
        .empty(buffer_empty), .prog_full(buffer_full));

    edge_info_mask_fifo_fall_through rf (
        .clk(clk), .srst(rst),
        .din(rf_in), .wr_en(front_any_dst_data_valid), .rd_en(!back_stage_vertex_full),

        .dout(top_edge_info_mask_r));

    // output
    generate
        genvar i;

        for (i = 0; i < EDGE_PIPE_NUM; i = i + 1) begin : M6_1_BLOCK_3
            always @ (posedge clk) begin
                if (rst) begin
                    tot_src_p_mask[i] <= 0;
                    tot_acc_id[(i + 1) * ACC_ID_WIDTH - 1 : i * ACC_ID_WIDTH] <= {ACC_ID_WIDTH{1'b1}};
                end
                else begin
                    if (!(buffer_empty || back_stage_vertex_full)) begin
                        if (i >= top_edge_info_mask_l && i <= top_edge_info_mask_r) begin
                            tot_src_p_mask[i] = 1'b1;
                            tot_acc_id[(i + 1) * ACC_ID_WIDTH - 1 : i * ACC_ID_WIDTH] <= FLAG;
                        end
                        else begin
                            tot_src_p_mask[i] <= 1'b0;
                            tot_acc_id[(i + 1) * ACC_ID_WIDTH - 1 : i * ACC_ID_WIDTH] <= {ACC_ID_WIDTH{1'b1}};
                        end
                    end
                    else begin
                        tot_src_p_mask[i] <= 1'b0;
                        tot_acc_id[(i + 1) * ACC_ID_WIDTH - 1 : i * ACC_ID_WIDTH] <= {ACC_ID_WIDTH{1'b1}};
                    end
                end
            end
        end
    endgenerate

endmodule

module get_edge_info_pre_1_vertex_single #(parameter
    VERTEX_MASK_WIDTH = `VERTEX_MASK_WIDTH, DST_ID_DWIDTH = `DST_ID_DWIDTH
    ) (
        input                                   clk,
        input                                   rst,
        input [DST_ID_DWIDTH - 1 : 0]           front_dst_id,
        input [VERTEX_MASK_WIDTH - 1 : 0]       front_edge_info_mask_r,
        input                                   front_dst_data_valid,
        input                                   front_any_dst_data_valid,
        input                                   back_stage_vertex_full,
        input                                   read_next_valid,

        output                                  buffer_empty,
        output                                  buffer_full,
        output                                  data_valid,
        output [DST_ID_DWIDTH - 1 : 0]          dst_id,
        output [VERTEX_MASK_WIDTH - 1 : 0]      src_p_mask_r,
        output                                  dst_data_valid);

    dst_id_fifo DI1 (
        .clk(clk), .srst(rst),
        .din(front_dst_id), .wr_en(front_any_dst_data_valid), .rd_en(!back_stage_vertex_full && read_next_valid),

        .dout(dst_id), .empty(buffer_empty), .prog_full(buffer_full));

    vertex_mask_fifo VM1 (
        .clk(clk), .srst(rst),
        .din(front_edge_info_mask_r), .wr_en(front_any_dst_data_valid), .rd_en(!back_stage_vertex_full && read_next_valid),

        .dout(src_p_mask_r));

    valid_fifo DDV1 (
        .clk(clk), .srst(rst),
        .din(front_dst_data_valid), .wr_en(front_any_dst_data_valid), .rd_en(!back_stage_vertex_full && read_next_valid),

        .dout(dst_data_valid), .valid(data_valid));

endmodule